#pragma once
#include <iostream>
#include <string>
#include <memory>
#include <jsoncpp/json/json.h>
#include <functional>
#include "Socket.hpp"

using namespace SocketModule;

// 自定义网络版本的计算器
// 客户端给服务器的请求类
class Request
{
public:
    Request() {}
    Request(int x, int y, char oper) : _x(x), _y(y), _oper(oper)
    {
    }
    std::string Serialize()
    {
        Json::Value root;
        root["x"] = _x;
        root["y"] = _y;
        root["oper"] = _oper;

        Json::FastWriter writer;
        std::string s = writer.write(root);
        return s;
    }
    bool Deserialize(std::string &in)
    {
        Json::Value root;
        Json::Reader reader;

        bool can = reader.parse(in, root);
        if (can)
        {
            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _oper = root["oper"].asInt();
        }

        return can;
    }
    int X() { return _x; }
    int Y() { return _y; }
    char Oper() { return _oper; }
    ~Request() {}

private:
    int _x;
    int _y;
    char _oper;
};

// 服务器处理完的结果给客户端的回应类
class Response
{
public:
    Response() {}
    Response(int result, int code) : _result(result), _code(code) {}
    std::string Serialize()
    {
        Json::Value root;
        root["result"] = _result;
        root["code"] = _code;

        Json::FastWriter writer;
        return writer.write(root);
    }
    bool Deserialize(std::string &in)
    {
        Json::Value root;
        Json::Reader reader;

        bool can = reader.parse(in, root);
        if (can)
        {
            _result = root["result"].asInt();
            _code = root["code"].asInt();
        }

        return can;
    }
    ~Response() {}
    void SetResult(int res)
    {
        _result = res;
    }
    void SetCode(int code)
    {
        _code = code;
    }
private:
    int _result;
    int _code; // 用于判断计算结果的正确性
};

const std::string sep = "\r\n";

using func_t = std::function<Response(Request &req)>;

// 协议需要解决:读取数据完整
// Protocal 类专注于协议解析（如将字节流解析为HTTP请求、RPC调用等）,而不应直接管理网络I/O或客户端身份.
class Protocal
{
public:
    Protocal(func_t func) : _func(func) {}
    // 封装序列化后的字符串
    std::string Encode(const std::string jsonstr)
    {
        std::string len = std::to_string(jsonstr.size());
        return len + sep + jsonstr + sep; // 封装报头
    }
    bool Decode(std::string &buffer, std::string *package) // 对封装后的报头进行解析
    {
        // 得到包头种类繁多,需要额外进行严格性判断
        // 1. 所以需要判断报文完整性
        // 2. 需要提取一个完整的报文并从缓冲区移除已经处理完的报文

        auto pos = buffer.find(sep);
        if (pos == std::string::npos)
            return false;                                    // 说明缓冲区不可能含有一个完整的包头,让调用方继续从内核读取数据
        std::string package_len_str = buffer.substr(0, pos); // 读取报头的长度
        int package_len_int = std::stoi(package_len_str);
        // 一定有长度,不代表有完整的包头,需要额外继续判断,判断逻辑如下:
        int target_len = package_len_str.size() + package_len_int + 2 * sep.size(); // 数字长度 + Json串长度 + 两倍分隔符长度 -> 一个完整报头的长度
        if (buffer.size() < target_len)
            return false;
        // 一定至少有一个完整的报头
        *package = buffer.substr(pos + sep.size(), package_len_int); // 提取报头信息
        buffer.erase(0, target_len);                                 // 将已经提取且处理完的完整报文的信息从内核缓冲区删除
        return true;
    }

    // std::shared_ptr<Socket> 是服务器与客户端通信的唯一通道。每个客户端连接对应一个独立的套接字对象，用于：
    // 读取请求：通过套接字的 read 或 recv 方法接收客户端发送的数据。
    // 发送响应：通过套接字的 write 或 send 方法将处理后的数据返回给客户端。
    // 客户端地址（InetAddr）的作用：身份标识与验证
    // 地址信息的内容：
    // InetAddr 封装了客户端的IP地址和端口号（如 192.168.1.100:54321），是客户端在网络中的唯一标识。
    void GetRequest(std::shared_ptr<Socket> &sock, InetAddr &client)
    {
        // 从内核缓冲区中读取报文信息
        std::string buffer_queue;
        while (true)
        {
            int n = sock->Recv(&buffer_queue); // 里面的内容可能越来越多,因为是传递的是地址,无法保证读取的数据是否完整,需要额外进行判断
            if (n > 0)
            {
                std::string json_package;                       // 用于提取信息的变量
                bool ret = Decode(buffer_queue, &json_package); // 解析报文完整性
                if (!ret)                                       // 不完整直接跳过提取信息的过程
                    continue;
                // 可以确定一定拿到完整报文信息
                // 对序列化串反序列化为原始数据结构对象
                Request req;
                bool can = req.Deserialize(json_package);
                if (!can) // 因为信息不符,提取失败,直接跳过即可
                    continue;
                // 完成业务功能
                Response resp = _func(req);

                // 把结果返回给客户端,序列化
                std::string json_str = resp.Serialize();

                // 反序列化
                std::string send_str = Encode(json_str); // 封装完后的应答报文

                // 发送信息
                sock->Send(send_str);
            }
            else if (n == 0)
            {
                LOG(LogLevel::INFO) << "client:" << client.StringAddr() << "quit!";
                break;
            }
            else
            {
                LOG(LogLevel::WARNING) << "client:" << client.StringAddr() << ",recv error";
                break;
            }
        }
    }
    ~Protocal() {}

private:
    // Request _req;
    // Response _resp;
    func_t _func;
};
